package top.wshape1.rpc.spring;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import top.wshape1.rpc.common.constant.RpcFilterType;
import top.wshape1.rpc.config.JJRpcConfig;
import top.wshape1.rpc.filter.Filter;
import top.wshape1.rpc.filter.FilterChainFactory;
import top.wshape1.rpc.spring.annotation.JJReference;
import top.wshape1.rpc.spring.annotation.RpcFilter;

import java.lang.reflect.Field;

/**
 * @author Wshape1
 * @version 1.0
 * @description
 * @since 2024-02-19
 */

@Slf4j
public class ConsumerPostProcessor implements BeanPostProcessor, InitializingBean {
    @Override
    public void afterPropertiesSet() {
        JJRpcConfig.CONFIG.getConsumer().setEnabled(true);
        JJRPCHolder.getJJRPC().startConsumer();
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, @NonNull String beanName) throws BeansException {
        Class<?> clazz = bean.getClass();

        // JJReference 注解
        for (Field field : clazz.getDeclaredFields()) {
            JJReference annotation = field.getAnnotation(JJReference.class);
            if (annotation != null) {
                try {
                    // 依赖注入
                    Object proxy = JJRPCHolder.getJJRPC().getService(field.getType());
                    field.setAccessible(true);
                    field.set(bean, proxy);
                    field.setAccessible(false);
                } catch (Exception e) {
                    log.error("Inject {} reference error: {}", field.getType().getName(), e.getMessage(), e);
                    throw new RuntimeException(e);
                }
            }
        }

        // RpcFilter 注解
        if (bean instanceof Filter) {
            RpcFilter annotation = clazz.getAnnotation(RpcFilter.class);
            if (annotation != null) {
                for (RpcFilterType rpcFilterType : annotation.value()) {
                    if (rpcFilterType == RpcFilterType.CONSUMER_SEND_REQUEST) {
                        FilterChainFactory.getConsumerSendReqFilterChain().addFilter((Filter) bean);
                    } else if (rpcFilterType == RpcFilterType.CONSUMER_RECEIVE_RESPONSE) {
                        FilterChainFactory.getConsumerRecRespFilterChain().addFilter((Filter) bean);
                    }
                }

            }
        }

        return bean;
    }
}
